﻿namespace BM.Tools.WebControls.MForm.Navigation
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using BM.Tools.WebControls.MForm.Controls;
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;

    /// <summary>
    /// A static class that contains extension methods for querying offspring items
    /// </summary>
    public static class StaticOffspringQuery
    {
        /// <summary>
        /// filters items to return only branch items
        /// </summary>
        /// <param name="items">
        /// The items.
        /// </param>
        /// <returns>
        /// the enumeration of branch items
        /// </returns>
        public static IEnumerable<BranchItem> Branches(this IEnumerable<OffspringItem> items)
        {
            return items.OfType<BranchItem>();
        }

        /// <summary>
        /// filters items to return only choice items
        /// </summary>
        /// <param name="items">
        /// The items.
        /// </param>
        /// <returns>
        /// the enumeration of choice items
        /// </returns>
        public static IEnumerable<ChoiceItem> Choices(this IEnumerable<OffspringItem> items)
        {
            return items.OfType<ChoiceItem>();
        }

        /// <summary>
        /// returns only items that inherit from a specific type
        /// </summary>
        /// <param name="items">
        /// The items to be filtered.
        /// </param>
        /// <param name="type">
        /// The type to be filtered with.
        /// </param>
        /// <returns>
        /// enumeration of items with a specific type
        /// </returns>
        public static IEnumerable<OffspringItem> FilterType(this IEnumerable<OffspringItem> items, OffspringType type)
        {
            switch (type)
            {
                case OffspringType.Offspring:
                    return items;
                case OffspringType.Branch:
                    return items.Branches().OfType<OffspringItem>();
                case OffspringType.Leaf:
                    return items.Leafs().OfType<OffspringItem>();
                case OffspringType.Choice:
                    return items.Choices().OfType<OffspringItem>();
                case OffspringType.OffspringsOwner:
                    return items.OfType<OffspringsOwnerItem>().OfType<OffspringItem>();
                case OffspringType.Root:
                    return items.OfType<RootItem>().OfType<OffspringItem>();
            }

            return null;
        }

        /// <summary>
        /// returns all children of the item
        /// </summary>
        /// <param name="item">
        /// The parent item
        /// </param>
        /// <returns>
        /// the enumeration of children items
        /// </returns>
        public static IEnumerable<OffspringItem> FindChildren(this OffspringItem item)
        {
            return item.FindChildren(child => true);
        }

        /// <summary>
        /// returns all children of the item that match the specified predicate
        /// </summary>
        /// <param name="item">
        /// The parent item
        /// </param>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// the enumeration of children items
        /// </returns>
        public static IEnumerable<OffspringItem> FindChildren(
                this OffspringItem item, Func<OffspringItem, bool> predicate)
        {
            var ownerItem = item as OffspringsOwnerItem;
            if (ownerItem == null)
            {
                return new OffspringItem[0];
            }

            return ownerItem.ChildItems.Where(predicate);
        }

        /// <summary>
        /// returns all children with matching local name
        /// </summary>
        /// <param name="item">
        /// The parent item.
        /// </param>
        /// <param name="localName">
        /// The local name.
        /// </param>
        /// <returns>
        /// the enumeration of children items
        /// </returns>
        public static IEnumerable<OffspringItem> FindChildrenByLocalName(this OffspringItem item, string localName)
        {
            return item.FindChildren(child => child.LocalName.Equals(localName));
        }

        /// <summary>
        /// returns all children with matching name
        /// </summary>
        /// <param name="item">
        /// The parent item.
        /// </param>
        /// <param name="name">
        /// The query name.
        /// </param>
        /// <returns>
        /// the enumeration of children items
        /// </returns>
        public static IEnumerable<OffspringItem> FindChildrenByName(this OffspringItem item, string name)
        {
            return item.FindChildren(child => child.NameEquals(name));
        }

        /// <summary>
        /// returns all children with matching prefix
        /// </summary>
        /// <param name="item">
        /// The parent item.
        /// </param>
        /// <param name="prefix">
        /// The query prefix.
        /// </param>
        /// <returns>
        /// the enumeration of children items
        /// </returns>
        public static IEnumerable<OffspringItem> FindChildrenByPrefix(this OffspringItem item, string prefix)
        {
            return item.FindChildren(child => child.Prefix.Equals(prefix));
        }

        /// <summary>
        /// returns all descendants of the item and itself
        /// </summary>
        /// <param name="item">
        /// The item from which the collection is started.
        /// </param>
        /// <returns>
        /// the enumeration of descendant items and self
        /// </returns>
        public static IEnumerable<OffspringItem> GetDescendantsAndSelf(this OffspringItem item)
        {
            yield return item;
            foreach (var child in item.FindChildren())
            {
                foreach (var descendant in child.GetDescendantsAndSelf())
                {
                    yield return descendant;
                }
            }
        }

        /// <summary>
        /// returns itself as an enumeration
        /// </summary>
        /// <param name="item">
        /// The item on which the operation is made.
        /// </param>
        /// <returns>
        /// the enumeration with the self
        /// </returns>
        public static IEnumerable<OffspringItem> GetSelf(this OffspringItem item)
        {
            yield return item;
        }

        /// <summary>
        /// returns information if the item's leaf type is attribute
        /// </summary>
        /// <param name="item">
        /// The item on which the operation is made.
        /// </param>
        /// <returns>
        /// is item's leaf type attribute
        /// </returns>
        public static bool IsAttribute(this OffspringItem item)
        {
            var leafItem = item as LeafItem;
            if (leafItem == null)
            {
                return false;
            }

            return leafItem.LeafType == LeafType.Attribute;
        }

        /// <summary>
        /// returns information if the item's leaf type is element
        /// </summary>
        /// <param name="item">
        /// The item on which the operation is made.
        /// </param>
        /// <returns>
        /// is item's leaf type element
        /// </returns>
        public static bool IsElement(this OffspringItem item)
        {
            var leafItem = item as LeafItem;
            if (leafItem == null)
            {
                return true;
            }

            return leafItem.LeafType == LeafType.Element;
        }

        /// <summary>
        /// filters items to return only leaf items
        /// </summary>
        /// <param name="items">
        /// The items.
        /// </param>
        /// <returns>
        /// the enumeration of leaf items
        /// </returns>
        public static IEnumerable<LeafItem> Leafs(this IEnumerable<OffspringItem> items)
        {
            return items.OfType<LeafItem>();
        }

        /// <summary>
        /// Checks if the item is a prototype or a prototype descendant.
        /// </summary>
        /// <param name="item">
        /// The item that is tested.
        /// </param>
        /// <returns>
        /// true if the item is a prototype descendant.
        /// </returns>
        public static bool IsPrototypeDescendant(this OffspringItem item)
        {
            if (item.ParentItem == null)
            {
                return false;
            }

            return item.IsPrototypeItem || item.ParentItem.IsPrototypeDescendant();
        }

        /// <summary>
        /// returns information if the item's name equals the specified value
        /// </summary>
        /// <param name="item">
        /// The item on which the operation is made.
        /// </param>
        /// <param name="name">
        /// The name to be compared.
        /// </param>
        /// <returns>
        /// does the item's name equal the specified value
        /// </returns>
        public static bool NameEquals(this OffspringItem item, string name)
        {
            return item.Name.Equals(name);
        }
    }
}